package model.simulation;

import model.dynamic.DyDepartment;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

//等级
public class RankLayer
{
	// 等级提升比例
	public final double[] promoteRates = DyDepartment.promoteRates;
	// 等级最低服役年限
	public static final int[] rankLeastTimes = DyDepartment.rankLeastTimes;
	// 等级最高服役年限
	public static final int[] rankLimitTimes = DyDepartment.rankLimitTimes;
	// 等级最高服役年龄
	public static final int[] rankLimitAges = DyDepartment.rankLimitAges;
	// 等级参考最低年龄
	static final int[] rankLowReferAges = DyDepartment.rankLowReferAges;

	static List<RankLayer> rankLayers;
	static List<SiDDepartment> siDDepartments;

	public static void initDatas(List<SiDDepartment> siDDepartments)
	{
		RankLayer.siDDepartments = siDDepartments;
		for (SiDDepartment siDDepartment : siDDepartments)
			siDDepartment.initMatch();
		rankLayers = new ArrayList<>();
		int index = 0;
		for (int i = 0; i < rankLimitTimes.length; i++)
		{
			if (i < 2 || i == 4 || i == 9)
				continue;
			RankLayer rankLayer = new RankLayer();
			rankLayer.index = index++;
			rankLayer.rankLimitAge = rankLimitAges[i];
			rankLayer.rankLowReferAge = rankLowReferAges[i];
			for (SiDDepartment siDDepartment : siDDepartments)
			{
				for (SiModel authorizedModel : siDDepartment.siAuthorizedModels)
					if (authorizedModel.getRank() == i + 1)
						rankLayer.authorizedModels.add(authorizedModel);
				for (SiModel actualModel : siDDepartment.siActualModels)
					if (actualModel.getRank() == i + 1)
						rankLayer.actualModels.add(actualModel);
				for (SiModel siModel : siDDepartment.notTotalMatchModels)
					if (siModel.getRank() == i + 1)
						rankLayer.notMatchModels.add(siModel);
			}
			rankLayers.add(rankLayer);
		}
	}

	public static void calculateNextYearDatas()
	{
		int n = 0;
		for (int i = rankLayers.size() - 1; i >= 0; i--)
			n += rankLayers.get(i).changInNextYear();

		System.out.println("退役数：" + n);

		for (SiDDepartment siDDepartment : siDDepartments)
		{
			siDDepartment.changInNextYear();
		}

		for (SiDDepartment siDDepartment : siDDepartments)
		{
			siDDepartment.calculateStatisticData();
		}
	}

	public static void nextYear()
	{
		int n = 0;
		for (int i = rankLayers.size() - 1; i >= 0; i--)
			n += rankLayers.get(i).changInNextYear();

		System.out.println("退役数：" + n);

		for (SiDDepartment siDDepartment : siDDepartments)
		{
			siDDepartment.changInNextYear();
		}
	}

	public RankLayer()
	{
	}

	int index;
	int rankLimitAge, rankLowReferAge;
	final List<SiModel> authorizedModels = new ArrayList<>();// 本级岗位编制
	List<SiModel> actualModels = new ArrayList<>();// 本级实有人员
	List<SiModel> notMatchModels = new ArrayList<>();// 本级编制不匹配人员
	List<SiModel> promoteModels = new ArrayList<>();// 本级下一年提升的人员
	List<SiModel> vacantAuthorizedModels = new ArrayList<>();// 本级下一年空缺出来的编制


	// 本级下一年空缺出来的编制
	List<SiModel> getVacantAuthorizedModels()
	{
		vacantAuthorizedModels.clear();
		for (SiModel authorizedModel : authorizedModels)
			if (authorizedModel.matchActualModel == null)
				vacantAuthorizedModels.add(authorizedModel);
		return vacantAuthorizedModels;
	}

	public int changInNextYear()
	{
		boolean[] bools;
		promoteModels.clear();
		List<SiModel> retireModels = new ArrayList<>();
		// 最高等级的情况
		if (index == rankLayers.size() - 1)
		{
			for (SiModel siModel : actualModels)
			{
				bools = siModel.changInNextYear();
				if (bools[0])
				{
					siModel.retire();
					retireModels.add(siModel);
				}
			}
			actualModels.removeAll(retireModels);
//			notTotalMatchModels.removeAll(retireModels);
//			match(notTotalMatchModels, vacantAuthorizedModels);
			return retireModels.size();
		}

		List<SiModel> tempPromoteModels = new ArrayList<>();
		for (SiModel siModel : actualModels)
		{
			bools = siModel.changInNextYear();
			if (bools[0])
			{
				siModel.retire();
				retireModels.add(siModel);
			} else if (bools[1])
				tempPromoteModels.add(siModel);
		}
		actualModels.removeAll(retireModels);
//		notTotalMatchModels.removeAll(retireModels);
		List<SiModel> highRankVacantAuthorizedModels = rankLayers.get(index + 1)
				.getVacantAuthorizedModels();
//		List<SiModel> highRankNotTotalMatchModels = rankLayers
//				.get(index + 1).notTotalMatchModels;
		int highRankVacantAuthorizedNumber = highRankVacantAuthorizedModels.size();
		if (tempPromoteModels.size() > highRankVacantAuthorizedNumber)
		{
			int[] randomIndexes = getRandomDifferInts(tempPromoteModels.size());
			for (int i = 0; i < highRankVacantAuthorizedNumber; i++)
				promoteModels.add(tempPromoteModels.get(randomIndexes[i]));
		} else
			promoteModels.addAll(tempPromoteModels);
		actualModels.removeAll(promoteModels);
		rankLayers.get(index + 1).actualModels.addAll(promoteModels);
//		notTotalMatchModels.removeAll(promoteModels);
		matchHighRank(promoteModels, highRankVacantAuthorizedModels);
//		matchHighRank(promoteModels, highRankVacantAuthorizedModels,
//				highRankNotTotalMatchModels);
//		match(notTotalMatchModels, vacantAuthorizedModels);

		// 最低等级的情况
		if (index == 0)
		{
//			int matchNumber = (int) (vacantAuthorizedModels.size() * 0.9);
//			int[] randomIndexes = getRandomDifferInts(
//					vacantAuthorizedModels.size() - 1);
			List<SiModel> tempVacantAuthorizedModels = getVacantAuthorizedModels();
//			tempVacantAuthorizedModels.addAll(getVacantAuthorizedModels());
			Random random = new Random();
//			for (int i = 0; i < matchNumber; i++)
//			{
//				
//				tempVacantAuthorizedModels.remove(randomIndexes[i]);
//				SiModel siModel = new SiModel(
//						vacantAuthorizedModels.get(randomIndexes[i]));
//				siModel.setRankServiceTime(1);
//				siModel.setServiceAge(rankLowReferAge
//						+ getGaussian(random, rankLimitAge - rankLowReferAge));
//				actualModels.add(siModel);
//			}

			for (SiModel authorizedModel : tempVacantAuthorizedModels)
			{
				SiModel siModel = new SiModel(authorizedModel);
				siModel.initMatchAuthorizedModel(authorizedModel);
				siModel.setRankServiceTime(1);
				siModel.setServiceAge(rankLowReferAge
						+ getGaussian(random, rankLimitAge - rankLowReferAge));
				actualModels.add(siModel);
			}

			System.out.println("补入数：" + tempVacantAuthorizedModels.size());
		}
		return retireModels.size();
	}

	static int getGaussian(Random random, int range)
	{
		double half = range / 2.0;
		int g = (int) (random.nextGaussian() / 2 * half + half);
		return g < 0 ? 0 : Math.min(g, range);
	}

	// 匹配上级岗位
	void matchHighRank(List<SiModel> promoteModels,
			List<SiModel> highRankVacantAuthorizedModels)
	{
		// 未匹配人员链表
		List<SiModel> matchModels = new ArrayList<>();
		for (SiModel promoteModel : promoteModels)
		{
			for (SiModel authorizedModel : highRankVacantAuthorizedModels)
			{
				if (promoteModel.isQuarterProfessionMatch(authorizedModel))// 是否岗位和专业匹配
				{
					promoteModel.promote(authorizedModel);
					matchModels.add(promoteModel);
					highRankVacantAuthorizedModels.remove(authorizedModel);
					break;
				}
			}
		}
		promoteModels.removeAll(matchModels);
		matchModels.clear();

		for (SiModel promoteModel : promoteModels)
		{
			for (SiModel authorizedModel : highRankVacantAuthorizedModels)
			{
				if (promoteModel.isProfessionMatch(authorizedModel))// 是否专业匹配
				{
					promoteModel.promote(authorizedModel);
					matchModels.add(promoteModel);
					highRankVacantAuthorizedModels.remove(authorizedModel);
					break;
				}
			}
		}
		promoteModels.removeAll(matchModels);
		matchModels.clear();
		for (SiModel promoteModel : promoteModels)
		{
			for (SiModel authorizedModel : highRankVacantAuthorizedModels)
			{
				if (promoteModel.isQuarterMatch(authorizedModel))// 是否岗位匹配
				{
					promoteModel.promote(authorizedModel);
					matchModels.add(promoteModel);
					highRankVacantAuthorizedModels.remove(authorizedModel);
					break;
				}
			}
		}
		promoteModels.removeAll(matchModels);
		int index = 0;
		for (SiModel promoteModel : promoteModels)
			promoteModel.promote(highRankVacantAuthorizedModels.get(index++));
	}

	// 匹配本级人员
	public void match(List<SiModel> notMatchModels,
			List<SiModel> vacantAuthorizedModels)
	{
		List<SiModel> tempVacantAuthorizedModels = new ArrayList<>();
		List<SiModel> removeModels = new ArrayList<>();
		List<SiModel> removeModels2 = new ArrayList<>();
		for (SiModel authorizedModel : vacantAuthorizedModels)
		{
			for (SiModel siModel : notMatchModels)
				if (authorizedModel.isTotalMatch(siModel))
				{
					if (siModel.matchAuthorizedModel != null)
						tempVacantAuthorizedModels.add(siModel.matchAuthorizedModel);
					siModel.matchAuthorizedModel(authorizedModel);
					removeModels.add(siModel);
					removeModels2.add(authorizedModel);
					break;
				}
		}
		notMatchModels.removeAll(removeModels);
		vacantAuthorizedModels.removeAll(removeModels2);
		vacantAuthorizedModels.addAll(tempVacantAuthorizedModels);
	}

//	public static int[] getRandomDifferInts(int n, int length)
//	{
//		return getRandomDifferInts(0, n, length);
//	}
//	public static int[] getRandomDifferInts(int min, int max, int length)
//	{
//		int n = max - min + 1;
//		if (n <= 0 || length <= 0)
//			return null;
//		if (length > n)
//			length = n;
//		int[] nums = new int[length];
//		Random rand = new Random();
//		boolean[] bool = new boolean[n];
//		int randInt = 0;
//		for (int i = 0; i < length; i++)
//		{
//			do
//			{
//				randInt = rand.nextInt(n);
//			} while (bool[randInt]);
//			bool[randInt] = true;
//			nums[i] = randInt + min;
//			// System.out.println(randInt);
//		}
//		return nums;
//	}

	public static int[] getRandomDifferInts(int size)
	{
		if (size <= 0)
			return null;
		int[] values = new int[size];
		int temp1, temp2, temp3;
		Random rand = new Random();
		for (int i = 0; i < values.length; i++)
			values[i] = i;
		// 随机交换
		for (int i = 0; i < values.length; i++)
		{
			temp1 = rand.nextInt(values.length); // 随机产生一个位置
			temp2 = rand.nextInt(values.length); // 随机产生另一个位置
			if (temp1 != temp2)
			{
				temp3 = values[temp1];
				values[temp1] = values[temp2];
				values[temp2] = temp3;
			}
		}
		return values;
	}
}
